# -*- coding: utf-8 -*-

## Copyright © 2014 Steven D'Aprano.

## Permission is hereby granted, free of charge, to any person obtaining a
## copy of this software and associated documentation files (the "Software"),
## to deal in the Software without restriction, including without limitation
## the rights to use, copy, modify, merge, publish, distribute, sublicense,
## and/or sell copies of the Software, and to permit persons to whom the
## Software is furnished to do so, subject to the following conditions:

## The above copyright notice and this permission notice shall be included in
## all copies or substantial portions of the Software.

## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
## IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
## FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
## THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
## LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
## FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
## DEALINGS IN THE SOFTWARE.


"""Enable tab completion and command line history.

Prior to Python 3.4, tab completion and command line history (for brevity,
"completion") has been supported but not enabled by default in the Python
interactive interpreter. This module enables and manages completion for
versions of Python 2.4 through 3.3. It will also work in 3.4 if for some
reason you don't like the standard completion functionality.

Requirements
============

This requires your version of Python to have been built with ``readline``
support. That includes most recent versions of Python. If you can import
the readline and rlcompleter modules, it should be fine.

Simply importing this module is enough to enable tab completion and
history, but for additional control two instances are exposed. Put this
in your Python startup file::

    from tabhistory import history, completer


Interactive Usage
=================

Normal command line history is enabled. Use the up and down arrow keys
to cycle through history, ENTER to accept the current line. History is
automatially saved when you exit the Python interpreter, and loaded when
you start it up again.

By default, pressing the TAB key supports four different tab completion
behaviours:

* at the start of the line, pressing the TAB key indents the line;

* inside strings, pressing TAB attempts filename completion of the string;

* following the ``import`` or ``from`` keywords, pressing TAB completes on
  modules or attributes;

* everywhere else, pressing TAB completes on keywords, built-ins, globals,
  and references of the form "name.name". (See the ``rlcompleter`` module
  for further information about code completion).

See your system's readline documentation for more information on tab
completion and command line history.

Known Issues
============

- The readline library used on Macintoshes, "libedit", uses a different
  syntax to the UNIX "libreadline". Some readline bindings may not work
  correctly.

- Windows does not have readline support. It may or may not work with the
  third-party ``pyreadline`` project. (Untested.)

- Do not create more than one History or Completer instance at a time,
  the behaviour is currently undefined.

"""

# Keep this module compatible with Python 2.4 and better.

# TODO: add "operate and go next" functionality like in bash.

try:
    # Everything depends on readline.
    import readline
except ImportError:
    # May be Windows, so try using a substitute. (Untested.)
    import pyreadline as readline

import rlcompleter
import atexit
import os
import sys

from zipimport import zipimporter

# This will hold a tuple of filename extensions recognised by Python.
# We generate it lazily, the first time it's needed.
_suffixes = None


# === Backported features and 2/3 compatibility ===

try:
    any
except NameError:
    # Probably Python 2.4.
    def any(iterable):
        for predicate in iterable:
            if predicate:
                return True
        return False


# === Public utility functions ===

def isblank(s):
    """Return True if string s is empty or whitespace otherwise False.

    >>> isblank('  \\n')
    True
    >>> isblank('')
    True
    >>> isblank('xyz')
    False

    """
    if not isinstance(s, str):
        raise TypeError('expected a string, not %s' % type(s).__name__)
    return not s or s.isspace()


# === Private utility functions ===

def _get_suffixes():
    """Return a (cached) tuple of filename extensions used by Python.

    >>> '.py' in _get_suffixes()
    True

    """
    global _suffixes
    if _suffixes is None:
        # Get the list of filename extensions.
        try:
            # Python >= 3.3
            from importlib.machinery import all_suffixes
            _suffixes = all_suffixes()
        except ImportError:
            from imp import get_suffixes
            _suffixes = [s[0] for s in get_suffixes()]
        _suffixes = tuple(_suffixes)
    return _suffixes

def _unmatched_quote(s):
    """Return the position of the first unmatched quote in s, or None.

    >>> _unmatched_quote("xyz['abcdef']") is None
    True
    >>> _unmatched_quote("xyz['abcde")
    4

    """
    # FIXME this does not allow for escaped quotes.
    if '"' in s or "'" in s:
        p = None  # Position of unmatched quote (if any).
        q = None  # Quote we're looking for.
        for i,c in enumerate(s):
            if q and c == q:
                p = q = None
            elif not q and c in ('"', "'"):
                p = i
                q = c
    else:
        p = None
    assert p is None or (0 <= p < len(s) and s[p] in ('"', "'"))
    return p

def _is_package(where):
    extensions = ('py','pyc','pyo')
    op = os.path
    return (op.isdir(where) and any(op.exists(
            op.join(where, '__init__.%s' % ext)) for ext in extensions))

def _get_module_name(name, suffixes, keep_final_dot):
    """Return the module name, minus suffix, or None if not a module."""
    for suffix in suffixes:
        if name.endswith(suffix):
            name = name[:-len(suffix)]
            if name.endswith('/__init__'):
                if keep_final_dot: name = name[:-8]
                else: name = name[:-9]
            return name.replace('/', '.')
    return None

def _get_builtin_modules(prefix):
    """Return a set of built-in modules matching prefix."""
    matches = set()
    for name in sys.builtin_module_names:
        if name.startswith(prefix):
            matches.add(name)
    return matches

def _get_modules(location, prefix):
    """Return a set of module names from location, matching prefix."""
    if location == '':
        location = '.'
    if os.path.isdir(location):
        modules = _get_modules_from_directory(location, prefix)
    elif os.path.isfile(location):
        modules = _get_modules_from_zipfile(location, prefix)
    else:
        modules = set()
    return modules

def _get_modules_from_zipfile(filename, prefix):
    """Return module names matching prefix from a zip file."""
    assert os.path.isfile(filename)
    matches = set()
    # Zip importing only supports a subset of suffixes.
    suffixes = ('.py', '.pyc', '.pyo')
    try:
        # This is a little bit naughty, as we're using an internal
        # implementation detail here. If it fails, we simply don't
        # find any matches.
        files = list(zipimporter(filename)._files.keys())
    except Exception:
        files = []
    # Dotted package names appear with slashes inside zipfiles.
    keep_dot = prefix.endswith('.')
    prefix = prefix.replace('.', '/')
    for name in files:
        if name.startswith(prefix):
            name = _get_module_name(name, suffixes, keep_dot)
            if name is not None:
                matches.add(name)
    return matches

def _get_modules_from_directory(pathname, prefix):
    """Return module names matching prefix from a directory."""
    assert os.path.isdir(pathname)
    matches = set()
    suffixes = _get_suffixes()
    if '.' in prefix:
        # In this case, prefix is the beginning of a dotted package
        # name like `spam.eggs.xyz`. Starting relative to pathname,
        # we look for valid packages spam, spam.eggs, before finally
        # checking for a valid module or package xyz. Note that it is
        # possible that xyz could be empty.
        where = pathname
        package, prefix = prefix.rsplit('.', 1)
        for part in package.split('.'):
            where = os.path.join(where, part)
            if not _is_package(where):
                break
        else:  # for...else: runs when there was no break.
            # When we get here, where = pathname/spam/eggs/
            # and we want to match xyz inside where.
            files = os.listdir(where)
            for name in files:
                if name.startswith(prefix):
                    if _is_package(os.path.join(where, name)):
                        matches.add('.'.join([package, name]))
                    else:
                        name = _get_module_name(name, suffixes, False)
                        if name is not None:
                            matches.add('.'.join([package, name]))
    else:
        # In this case prefix is the beginning of an undotted module
        # name like `xyz`, so we just look directly in the given
        # pathname for a file (module) or directory (package) beginning
        # with xyz.
        files = os.listdir(pathname)
        for name in files:
            if name.startswith(prefix):
                if _is_package(os.path.join(pathname, name)):
                    matches.add(name)
                else:
                    name = _get_module_name(name, suffixes, False)
                    if name is not None:
                        matches.add(name)
    return matches

def _readline_lib():
    """Return the name of the underlying readline library."""
    # This tests for the libedit library instead of libreadline, which
    # may indicate OS-X or *BSD - See http://bugs.python.org/issue10666
    #
    # FIXME This is the canonical test as suggested by the docs, but
    # surely there is a better test than this? Perhaps something like
    # sys.platform == DARWIN?
    if 'libedit' in readline.__doc__:
        return 'libedit'
    return 'libreadline'

class _FauxLogger:
    """Fake do-nothing logger.

    >>> logger = _FauxLogger()
    >>> logger.debug("message") is None
    True

    """
    def __getattr__(self, name):
        return (lambda self, *args, **kwargs: None)


# === Readline tab completion and commandline history ===

class Completer(rlcompleter.Completer):
    """Readline tab completer with support for indenting.

    Creating a ``Completer`` instance automatically installs the completion
    functionality::

        >>> completer = Completer()  #doctest: +SKIP

    By default, the TAB key is used for both indenting and completion.

    Set the ``indent`` attribute to change the string used for indentation.
    While any string is permitted, only spaces or tabs make valid Python.
    Common values include '\\t' (tab), or '    ' (four spaces). Set it to
    None or the empty string to disable indenting and allow code completion
    at the beginning of lines.
    """
    LIBRARY = _readline_lib()
    logger = None  # Set an instance attribute to a logger for debugging.

    def __init__(self, namespace=None, key=None, indent='\t',
                       query_items=30, bindings=()):
        """Initialise a Completer instance.

        All arguments to the class constructor are optional.

        namespace:
            None, or a namespace dict, to use for completions. See the
            `rlcompleter` module for more details.

        key:
            Key to use for completion. `key` should be a key combination
            written in the appropriate syntax for your readline library.
            If `key` is not given or is None, the default TAB key will be
            used. Any other choice for `key` will be used exactly as given,
            and it is your responsibility to ensure it is in the correct
            syntax for the underlying readline library.

        indent:
            String to insert for indents when the completer key is pressed
            at the start of the line. The default is to insert a literal
            tab. Another common choice is four spaces. If you pass None or
            the empty string, pressing the completer key will *not* indent,
            but will perform code completion instead.

        query_items:
            The maximum number of items that the completer will show without
            asking first. The default is 30.

        bindings:
            A single string, or a tuple of strings, which will be passed to
            the ``bind`` method.

        """
        # This is a classic class in Python 2.x, so no super().
        rlcompleter.Completer.__init__(self, namespace)
        self.indent = indent
        self.set_completer(key)
        self.set_query_items(query_items)
        s = ('\x4e\x4f\x42\x4f\x44\x59\x20\x65\x78\x70\x65\x63\x74'
             '\x73\x20\x74\x68\x65\x20\x53\x70\x61\x6e\x69\x73\x68'
             '\x20\x49\x6e\x71\x75\x69\x73\x69\x74\x69\x6f\x6e\x21')
        self.bind(r'"\C-xi": "%s"' % s)
        if isinstance(bindings, str):
            bindings = (bindings,)
        self.bind(*bindings)

    # ----------------------------------------------------------
    # Public methods
    # ----------------------------------------------------------

    def bind(self, *bindings):
        """Parse and bind the given readline bindings.

        Each argument collected in the ``bindings`` argument should be
        a string, and will be parsed and bound by readline. See your
        operating system's readline documentation for syntax.
        """
        for binding in bindings:
            readline.parse_and_bind(binding)

    def unset_completer(self):
        """Unset the completer.

        Calling this disables command completion.
        """
        readline.set_completer(None)

    def set_completer(self, key):
        """Set the completer and bind to the given key.

        If ``key`` is None or the empty string, the completer is bound to
        the TAB key. For any other key binding, you are responsible for
        providing ``key`` which is a valid binding for your readline library.
        E.g. using libreadline, pass ``key='C-a'`` to bind to Ctrl-A.

        Note that different libraries may use different syntax.
        """
        if key is None or key == '':
            # Use the default completer key.
            key = self._tabkey()
        # Remove the previous completer (possibly installed by rlcompleter),
        # and set the new one.
        self.unset_completer()
        self.bind(self._generate_completer_template() % key)
        readline.set_completer(self.completer)

    def set_query_items(self, num):
        """Set the number of query items to num.

        This instructs readline to set the maximum number of items that the
        completer will show without asking first.
        """
        self.bind(self._generate_query_items() % num)

    def set_logger(self, filename):
        """Helper function that creates a logger for use in debugging.

        You can manually set the ``logger`` attribute to any logger instance,
        but as a convenience, the ``set_logger`` method takes a file name,
        creates a logger that writes to that file, and binds it to the
        ``logger`` attribute.

        To turn logging off again, simply set the ``logger`` attribute to
        None, or delete it.
        """
        import logging
        logger = logging.getLogger()
        logger.setLevel(logging.DEBUG)
        logger.addHandler(logging.FileHandler(filename))
        self.logger = logger
        logger.info('started logging')

    def completer(self, word, state):
        """Completer callback function, called by readline.

        This method is called by the readline library when you hit the
        completer key (TAB by default). It attempts to complete the current
        line as follows:

        * At the start of the line buffer, indent (by default).
        * After `from` or `import`, complete on module names.
        * After `from spam import`, complete on attributes of module `spam`.
        * Inside strings, complete on file names.
        * Everywhere else, perform code completion on names, keywords, etc.

        For more details on the types of code completion done, see the
        ``rlcompleter`` module.

        If self.logger is not None, it is expected to be a logger from the
        logging module. Debugging, warning and error messages will be logged.
        """
        logger = self._get_logger()
        try:
            if state == 0:
                # In the most general case, the line buffer has three parts:
                #   [prefix][word][suffix]
                #
                # where `word` is the part being completed. We don't care
                # about the suffix (if any), but we do care about the prefix.
                line = readline.get_line_buffer()
                prefix = line[:readline.get_begidx()]
                # Let's see what readline sees.
                logger.debug("prefix=%r  word=%r" % (prefix, word))
                chunk = line[readline.get_begidx():readline.get_endidx()]
                if word != chunk:
                    logger.warning('match text differs: %r != %r' % (word, chunk))
                self._create_match_list(prefix, word)
            # When we get here, self.matches is the list of candidates
            # for completion. Return the Nth match, for state=N.
            try:
                response = self.matches[state]
            except IndexError:
                response = None
            logger.debug("[state=%d] %r --> %r" % (state, word, response))
            return response
        except Exception:
            logger.exception('error in completer')

    # ----------------------------------------------------------
    # Private completer methods
    # ----------------------------------------------------------

    # The various _*_completion methods handle building the match list
    # various scenarios. They all operate by side-effect (blame the
    # rlcompleter module for that design decision), building the match
    # list and storing it as self.matches.
    #
    # The _create_match_list method is responsible for deciding which
    # of the completers to call.

    def _code_completion(self, word):
        """Build a match list of names, keywords, attributes, etc."""
        # Here we delegate to rlcompleter.Completer, and call its complete
        # method just for the side-effect, ignoring it's return result.
        # Yes, that is horrible.
        _ = rlcompleter.Completer.complete(self, word, 0)
        # Fix for this bug: http://bugs.python.org/issue22143
        self.matches = sorted(set(self.matches))

    def _filename_completion(self, pos, prefix, word):
        """Build a match list of filenames.

        Given a line buffer like this (for example):

            var = func("ab'c", "fee/fo/fum/foo<TAB>

        we expect to receive arguments:

            pos = 19  # position of the unmatched quote
            prefix = 'var = func("ab\'c", "fee/fo/fum/'
            word = 'foo'

        and to match on file names starting with foo inside fee/fo/fum/.
        Either single ' or double " quotes are permitted.
        """
        assert prefix[pos] in ('"', "'")
        # Extract the pathname leading to the filename:
        path = prefix[pos+1:]
        base, tail = os.path.split(path)
        if base == '':
            base = '.'
        tail += word
        # Generate a list of file names which match that prefix.
        matches = [f for f in os.listdir(base) if f.startswith(tail)]
        self.matches = sorted(matches)

    def _from_completion(self, terms, word):
        """Build a match list suitable to follow the `from` keyword.

        This can complete on either module names, module attributes
        (but only for modules already in sys.modules), or as a special
        case, insert the "import" keyword.

        The ``terms`` argument should be a list of words from the line
        buffer prefixing the word being completed.
        """
        assert terms[0] == 'from'
        if len(terms) == 1:
            # `from xyz<TAB>`
            self._module_completion(word)
        elif len(terms) == 2:
            # `from spam eggs<TAB>`
            # Only one thing can legally follow, it must be `import`.
            self.matches = ['import ', None]
        elif terms[2] == 'import':
            # `from spam import eggs,cheese,xyz<TAB>`
            module = terms[1]
            try:
                m = sys.modules[module]
            except KeyError:
                matches = []
            else:
                matches = [attr for attr in vars(m) if attr.startswith(word)]
            self.matches = sorted(matches)
        else:
            assert False, "this should never be called"

    def _module_completion(self, word):
        """Build a match list of modules or dotted package.modules."""
        if word.startswith('.'):
            # Relative imports `.xyz<TAB>` are not supported.
            self.matches = []
            return
        # `xyz<TAB>` and `spam.eggs.xyz<TAB>` are supported.
        matches = _get_builtin_modules(word)
        for location in sys.path:
            matches.update(_get_modules(location, word))
        self.matches = sorted(matches)

    def _indent_completion(self, indent):
        """Build a match list suitable for indenting."""
        if indent is None or indent == '':
            # Indenting has been disabled, so fall back on code completion.
            self._code_completion('')
        else:
            self.matches = [indent, None]

    def _create_match_list(self, prefix, word):
        """Create the match list holding candidates for word completion."""
        logger = self._get_logger()
        if isblank(prefix):
            if isblank(word):
                # `<blank><TAB>`
                logger.info('calling _indent_completion')
                self._indent_completion(self.indent)
            else:
                # `xyz<TAB>`
                logger.info('calling _code_completion')
                self._code_completion(word)
        else:
            terms = prefix.split()
            if terms[0] == 'import':
                # `import spam,xyz<TAB>`
                logger.info('calling _module_completion')
                self._module_completion(word)
            elif terms[0] == 'from':
                # `from xyz<TAB>` etc.
                logger.info('calling _from_completion')
                self._from_completion(terms, word)
            else:
                p = _unmatched_quote(prefix)
                if p is None:
                    logger.info('calling _code_completion')
                    self._code_completion(word)
                else:
                    # `something "filen<TAB>`
                    logger.info('calling _filename_completion')
                    self._filename_completion(p, prefix, word)

    # ----------------------------------------------------------
    # General private methods
    # ----------------------------------------------------------

    def _tabkey(self):
        """Return the string used to indicate the TABKEY."""
        if self.LIBRARY == 'libedit':
            # Probably Mac OS X or BSD.
            return '^I'
        else:
            # Most other Unix and Linux systems.
            return 'tab'

    def _generate_completer_template(self):
        """Generate the appropriate binding template for the tab completer."""
        if self.LIBRARY == 'libedit':
            return 'bind %s rl_complete'
        else:
            return '%s: complete'

    def _generate_query_items(self):
        """Generate the appropriate binding template for the query items."""
        # FIXME Will this work with libedit?
        return "set completion-query-items %d"

    ## Don't make this a property! In Python 2.x, this is a
    ## classic class where properties don't work correctly.
    def _get_logger(self):
        """Return either a logger, or a do-nothing fake logger."""
        logger = getattr(self, "logger", None)
        if logger is None:
            return _FauxLogger()
        return logger


class History(object):
    """Enable and control command-line history.

    Creating a ``History`` instance enables command-line history, reads in
    any existing content of the history file, and prepares to write history
    back to that file when Python exits::

        >>> history = History()  #doctest: +SKIP

    By default, the history file will be ".python_history" in the user's
    home directory. You can change that by setting the environment variable
    ``PYTHONHISTORYFILE`` to the path to the file you want.

    The history buffer will be automatically written to the history file
    when Python exits. You can write the history buffer to any file at any
    time by calling ``write_history`` method. You can also re-read from the
    history file, or any other text file, at any time: ``load_history``
    replaces the current history buffer with the content of the file, while
    ``read_history`` keeps any existing lines and appends to the buffer.

    You can control the maximum number of lines that will be written to a
    file by assigning to the ``history_length`` property at any time. By
    default that is set to 500 lines. Likewise you can change the history
    file by assigning to the ``history_file`` property.

    Calling the instance will display the latest few history lines::

        >>> history(4)  #doctest: +SKIP
        119: x = spam(23) + eggs(42)
        120: do_this()
        121: do_that()
        122: do_something_else()

    See the ``__call__`` method for further details.
    """
    DEFAULT_HISTORY_FILE = '~/.python_history'
    DEFAULT_HISTORY_LENGTH = 500
    MAX_LINES_TO_SHOW = 10  # Use < 0 for unlimited.

    def __init__(self, history_file=None, history_length=None):
        """Initialise a History instance and enable commandline history.

        Arguments::

            history_file:
                Optional name of the history file to use. If missing or
                None, uses the environment variable ``PYTHONHISTORYFILE``.
                If the empty string, or if the environment variable is
                not set, uses the class attribute ``DEFAULT_HISTORY_FILE``
                (defaults to ".python_history" in the user's home
                directory).

            history_length:
                The maximum number of lines which will be saved to the
                history file. If not given, or None, the class attribute
                ``DEFAULT_HISTORY_LENGTH`` (defaulting to 500) is used.

        """
        self.history_file = history_file
        self.history_length = history_length
        self.read_history(self.history_file)

    def __call__(self, count=None, show_line_numbers=True):
        """Print the latest `count` lines from the history.

        If `count` is None or not given, a default number of lines
        is shown, given by the attribute ``MAX_LINES_TO_SHOW``. Use
        a negative count to show unlimited lines.

        If ``show_line_numbers`` is true (the default), each history
        line is preceeded by the line number.
        """
        if count is None:
            count = self.MAX_LINES_TO_SHOW
        end = self.get_current_history_length()
        if count < 0:
            start = 1
        else:
            start = max(end - count + 1, 1)
        nums = range(start, end+1)
        lines = self.get_history_lines(start, end)
        if show_line_numbers:
            # Can't use {} formatting as we have to support 2.4 and 2.5.
            template = "%(lineno)3d:  %(line)s"
        else:
            template = "%(line)s"
        for i, line in zip(nums, lines):
            print(template % {'lineno':i, 'line':line})

    def _adjust_position(self, pos):
        """Return 0-based position from 1-based position.

        Weirdly, although readline.get_history_item() is 1-based, the other
        positional readline functions are 0-based. This leads to off-by-one
        errors. This converts a 1-based position to 0-based, and supports
        negative positions counting from the end.
        """
        if not isinstance(pos, int):
            raise TypeError('pos must be an int')
        if pos == 0:
            raise ValueError('pos starts from 1, not 0, and cannot be 0')
        elif pos > 0:
            return pos - 1
        else:
            assert pos < 0
            return self.get_current_history_length() + pos

    # Thin wrappers around readline functionality.

    def add_history(self, line):
        """Add line to the history buffer."""
        readline.add_history(line)

    def clear_history(self):
        """Clear the current history buffer."""
        readline.clear_history()

    def get_current_history_length(self):
        """Return the actual (not the maximum) length of the history buffer.

        To get the maximum length, inspect the instance.history_length
        property.
        """
        return readline.get_current_history_length()

    def get_history_lines(self, start=1, end=None):
        """Return history items between `start` and `end` inclusive.

        Unlike Python indexes, the readline history items are numbered
        from 1. If not given, ``start`` defaults to 1, and ``end``
        defaults to the latest item.
        """
        get = readline.get_history_item
        if end is None:
            end = readline.get_current_history_length()
        return [get(i) for i in range(start, end+1)]

    def load_history(self, filename=None):
        """Load history from the named file (if possible).

        If filename is None or missing, use the ``history_file`` attribute.

        This clears any existing history lines. To append to the existing
        history lines instead, use the ``read_history`` method.
        """
        self.clear_history()
        self.read_history(filename)

    def read_history(self, filename=None):
        """Read history from the named file (if possible).

        If filename is None or missing, use the ``history_file`` attribute.

        History lines read are appended to the current history buffer.
        To replace the current buffer, use the ``load_history`` method.
        """
        if filename is None:
            filename = self.history_file
        else:
            filename = os.path.expanduser(filename)
        try:
            readline.read_history_file(filename)
        except (IOError, OSError):
            pass

    def remove_history_item(self, pos):
        """Remove the history item at the given position.

        Unlike the readline function of the same name, the position here is
        1-based, matching that used by readline.get_history_item. Negative
        positions count from the end, so pos=-1 means the latest item.
        """
        pos = self._adjust_position(pos)
        readline.remove_history_item(pos)

    def replace_history_item(self, pos, line):
        """Replace the history item at the given position to the given line.

        Unlike the readline function of the same name, the position here is
        1-based, matching that used by readline.get_history_item. Negative
        positions count from the end, so pos=-1 means the latest item.
        """
        pos = self._adjust_position(pos)
        readline.replace_history_item(pos, line)

    def write_history(self, filename=None):
        """Write command line history to the named file without waiting
        for program exit.

        If `filename` is None or missing, use the ``history_file`` attribute.

        The maximum number of lines that will be written is controlled by
        the ``history_length`` property.
        """
        if filename is None:
            filename = self.history_file
        else:
            filename = os.path.expanduser(filename)
        readline.write_history_file(filename)

    # History setters/getters and properties.

    def _get_history_length(self):
        """Return the maximum number of lines which will be written
        to the history file.
        """
        return readline.get_history_length()

    def _set_history_length(self, length):
        """Set the maximum number of lines which will be written
        to the history file.

        A negative value means that unlimited lines will be written.
        """
        if length is None:
            length = self.DEFAULT_HISTORY_LENGTH
        if not isinstance(length, int):
            raise TypeError('history length must be an integer')
        # Set the maximum length of the history file.
        readline.set_history_length(length)

    history_length = property(_get_history_length, _set_history_length)
    del _get_history_length, _set_history_length

    def _get_history_file(self):
        return self._history_file

    def _set_history_file(self, filename):
        if filename is None:
            filename = os.getenv('PYTHONHISTORYFILE', '')
        if filename == '':
            filename = self.DEFAULT_HISTORY_FILE
        if not isinstance(filename, str):
            raise TypeError('history file name must be a str')
        self._history_file = os.path.expanduser(filename)
        # Save the history file when exiting.
        atexit.register(readline.write_history_file, self._history_file)

    history_file = property(_get_history_file, _set_history_file)
    del _get_history_file, _set_history_file



completer = Completer()
history = History()
